package cn.hzc.fortess.system.service;

import cn.hzc.fortess.core.common.HttpContext;
import cn.hzc.fortess.core.common.annotion.CURDLog;
import cn.hzc.fortess.core.common.annotion.CURDType;
import cn.hzc.fortess.core.common.constant.Const;
import cn.hzc.fortess.core.common.BizErrorEnum;
import cn.hzc.fortess.core.common.exception.ServiceException;
import cn.hzc.fortess.core.shiro.ShiroKit;
import cn.hzc.fortess.system.common.EnableStatus;
import cn.hzc.fortess.system.dao.DeptDao;
import cn.hzc.fortess.system.dao.RoleDao;
import cn.hzc.fortess.system.dao.UserDao;
import cn.hzc.fortess.system.entity.Role;
import cn.hzc.fortess.system.entity.User;
import cn.hzc.fortess.system.page.Pagination;
import cn.hzc.fortess.system.search.UserSearch;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpSession;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    MenuService menuService;

    @Autowired
    UserDao userDao;
    @Autowired
    DeptDao deptDao;

    @Autowired
    RoleService roleService;
    @Autowired
    RoleDao roleDao;
    @Autowired
    JwtTokenService jwtTokenService;


    @Override
    public User getById(Integer userId) {
        return userDao.findById(userId);
    }

    @Override
    public List<User> getUserByRole(Integer roleId) {
        List<User> users = userDao.getUserByRole(roleId);
        if (CollectionUtils.isEmpty(users)) {
            return Lists.newArrayList();
        }
        return users;
    }

    @Override
    public List<User> getUserByLessee(Integer lesseeId) {
        List<User> users = userDao.getUserByLessee(lesseeId);
        if (CollectionUtils.isEmpty(users)) {
            return Lists.newArrayList();
        }
        return users;
    }


    @Override
    public User getByLoginName(String account) {
        return userDao.getUserByAccount(account);
    }

    @Override
    public void changePwd(HttpSession session,Integer userId, String oldPassword, String newPassword) {
        User user = this.getById(userId);
        String oldMd5 = ShiroKit.md5(oldPassword, user.getSalt());

        if (user.getPassword().equals(oldMd5)) {
            String newMd5 = ShiroKit.md5(newPassword, user.getSalt());
            user.setPassword(newMd5);
            this.updateUserPwd(session,user);
            jwtTokenService.removeJwtToken(ShiroKit.getUser().getId());

        } else {
            throw new ServiceException(BizErrorEnum.OLD_PWD_NOT_RIGHT.getCode(), BizErrorEnum.OLD_PWD_NOT_RIGHT.getMessage());
        }
    }

    @Override
    @CURDLog(value = "新增用户")
    public void add(User entity) {
        entity.setSalt(ShiroKit.getRandomSalt());
        entity.setPassword(ShiroKit.md5(entity.getPassword(), entity.getSalt()));

        entity.setCreateTime(new Date());
        entity.setCreateUser(ShiroKit.getUser().getAccount());
        userDao.insert(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CURDLog(value = "编辑用户", curdType = CURDType.EDIT)
    public void update(User entity) {
        entity.setUpdateTime(new Date());
        entity.setUpdateUser(ShiroKit.getUser().getAccount());
        userDao.update(entity);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CURDLog(value = "删除用户", curdType = CURDType.DELETE)
    public void delete(Integer id) {
        userDao.delete(id);
        userDao.deleteRelationByUser(id);
        jwtTokenService.removeJwtToken(ShiroKit.getUser().getId());

    }

    @Override
    @CURDLog(value = "编辑用户状态", curdType = CURDType.EDIT)
    public void updateUserStatus(Integer userId, Integer status) {
        if(userDao.updateUserStatus(userId,status)<=0){
            throw  new RuntimeException("修改用户状态失败!");
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    @CURDLog(value = "删除部门所有用户", curdType = CURDType.DELETE)
    public void deleteByDept(Integer deptId) {
        List<User> users = userDao.findUserByDept(deptId);
        if (!CollectionUtils.isEmpty(users)) {
            users.stream().forEach(user -> delete(user.getUserId()));
        }
    }


    @Override
    public void updateUserPwd(HttpSession session, User user) {
        userDao.updateUserPwd(user);
        jwtTokenService.removeJwtToken(ShiroKit.getUser().getId());
        if(session!=null) {
            session.removeAttribute(Const.SESSION_WEAK_PWD_TIPS_KEY);
        }
    }

    @Override
    public Pagination getPage(UserSearch search) {
        Pagination pagination = new Pagination();
        pagination.setCount(userDao.count(search));
        if (pagination.getCount() > 0) {
            pagination.setData(userDao.page(search));
        }
        return pagination;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CURDLog(value = "设置用户角色", curdType = CURDType.SETTING)
    public void setRoles(final Integer userId, String[] rids) {

        final List<Role> userRoles = roleDao.findByUserId(userId);

        final List<String> roleIds = Arrays.asList(rids).parallelStream().filter(roleid -> StringUtils.isNotBlank(roleid)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(userRoles) && CollectionUtils.isEmpty(roleIds)) {
            return;
        }
        if (CollectionUtils.isEmpty(userRoles) && (!CollectionUtils.isEmpty(roleIds))) {
            roleIds.stream().forEach(roleid -> {
                userDao.addRoleByUser(userId, Integer.parseInt(roleid));
            });
            return;
        }
        if ((!CollectionUtils.isEmpty(userRoles)) && CollectionUtils.isEmpty(roleIds)) {
            if (ShiroKit.getUser().isAdministrator()) {
                userDao.clearRoleByUserId(userId);
            } else {
                userRoles.stream().filter(role -> role.getIsAdmin() != Const.YES).forEach(role -> roleDao.deleteRelationByRole(role.getId()));
            }
            return;
        }
        if (ShiroKit.getUser().isAdministrator()) {
            userDao.clearRoleByUserId(userId);
            roleIds.stream().forEach(roleid -> userDao.addRoleByUser(userId, Integer.parseInt(roleid)));
            return;
        }
        final Set<Integer> roles = Sets.newHashSet();
        userRoles.parallelStream().filter(role -> role.getIsAdmin() == Const.YES).forEach(role -> roles.add(role.getId()));
        roleIds.parallelStream().forEach(roleid -> roles.add(Integer.parseInt(roleid)));
        roles.stream().forEach(roleid -> {
            userDao.addRoleByUser(userId, roleid);
        });

    }

    @Override
    public boolean hasResourceAuth(Integer userId, String resourceAuthIdent) {

        User user = getById(userId);
        if (user == null || Objects.equals(user.getStatus(), EnableStatus.DISABLE.getStatus())) {
            return false;
        }
        if (Objects.equals(Const.ADMIN_USER_ID, user.getUserId())) {
            return true;
        }

        List<Role> roles = roleService.getByUser(userId);
        if (CollectionUtils.isEmpty(roles)) {
            return false;
        }
        List<String> resources = roleService.findMenuPermissionListByRoleIds(roles.parallelStream().map(Role::getId).collect(Collectors.toList()));
        if (CollectionUtils.isEmpty(resources)) {
            return false;
        }
        return resources.parallelStream().filter(ident -> {
            if (StringUtils.isBlank(ident)) {
                return false;
            }
            if (ident.equals(resourceAuthIdent)) {
                return true;
            }
            if (ident.indexOf(",") > -1) {
                for (String si : ident.split(",")) {
                    if (ident.equals(si)) {
                        return true;
                    }
                }
            }
            return false;
        }).count() > 0;
    }

}
